package com.flqy.baselibrary.utils;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.provider.MediaStore;

import androidx.fragment.app.Fragment;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;

import android.util.Log;
import android.util.TypedValue;
import android.widget.Toast;

import com.flqy.baselibrary.BaseApp;
import com.flqy.baselibrary.R;
import com.flqy.baselibrary.utils.luban.Luban;
import com.tbruyelle.rxpermissions2.RxPermissions;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SyncFailedException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

public class Utils {
    private static final long LOW_STORAGE_THRESHOLD = 1024 * 1024 * 15;
    private static final String TEMP_IMAGE_NAME = "_temp.jpg";
    public static final int QUALITY_NOT_WIFI = 70;

    public static final int QUALITY_WIFI = 80;

    public static int getColorPrimary(Context context) {
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
        return typedValue.data;
    }

    public static int getColorAccent(Context context) {
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
        return typedValue.data;
    }


    public static void takePhoto(final Activity activity, final int requestCode, final File imagePath) {
        RxPermissions rxPermissions = new RxPermissions(activity);
        rxPermissions.request(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE).subscribe(new Observer<Boolean>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(Boolean aBoolean) {
                if (Utils.checkSdCardAvailable()) {
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    if (imagePath.exists())
                        imagePath.delete();
                    Uri outputFileUri = getFileUri(activity, imagePath);
                    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
                    if (intent.resolveActivity(activity.getPackageManager()) != null) {
                        activity.startActivityForResult(intent, requestCode);
                    }
                } else {
                    Toast.makeText(activity, "存储空间容量不足!", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onError(Throwable e) {
                Toast.makeText(activity, "获取相机权限失败!", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onComplete() {

            }
        });

    }

    public static Uri getFileUri(Context context, File file) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
        } else {
            return Uri.fromFile(file);
        }
    }

    private static final String UPLOAD_DIR_NAME = "upload_dir";

    public static File getCameraImagePath(Context context) {
        return new File(getExistCacheDir(context, UPLOAD_DIR_NAME), TEMP_IMAGE_NAME);
    }

    public static void takePhoto(Fragment fragment, int requestCode) {
        takePhoto(fragment, requestCode, getCameraImagePath(fragment.getActivity()));
    }

    public static void takePhoto(final Fragment fragment, final int requestCode, final File imagePath) {
        RxPermissions rxPermissions = new RxPermissions(fragment.getActivity());
        rxPermissions.request(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(new Observer<Boolean>() {
            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(Boolean aBoolean) {
                int permissionCheck = ContextCompat.checkSelfPermission(fragment.getActivity(), Manifest.permission.CAMERA);
                if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
                    if (Utils.checkSdCardAvailable()) {
                        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        if (imagePath.exists())
                            imagePath.delete();
                        Uri outputFileUri = getFileUri(fragment.getActivity(), imagePath);
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
                        if (intent.resolveActivity(fragment.getActivity().getPackageManager()) != null) {
                            Log.i("TedBottomPicker", "start camera for result");
                            fragment.startActivityForResult(intent, requestCode);
                        }
                    } else {
                        Log.i("TedBottomPicker", "sdcard error");
                        Toast.makeText(fragment.getActivity(), "存储空间容量不足!", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Log.i("TedBottomPicker", "quanxian error");
                    Toast.makeText(fragment.getActivity(), "权限不足，请请开启相机权限！", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onError(Throwable e) {
                Toast.makeText(fragment.getActivity(), "获取相机权限失败!", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onComplete() {

            }
        });

    }

    /**
     * Get a usable cache directory (external if available, internal otherwise).
     *
     * @param uniqueName A unique directory name to append to the cache dir
     * @return The cache dir
     */
    @Deprecated
    public static File getDiskCachePath(Context context, String uniqueName) {

        // Check if media is mounted or storage is built-in, if so, try and use
        // external cache dir
        // otherwise use internal cache dir
        final String cachePath = Utils.isExternalStorageMounted() ? Utils.getExternalCacheDir(context).getPath() : context.getCacheDir().getPath();
        if (uniqueName != null) {
            return new File(cachePath + File.separator + uniqueName);
        } else {
            return new File(cachePath);
        }
    }

    public static File getExistCacheDir(Context context, String uniqueName) {
        if (Utils.isExternalStorageMounted()) {
            File dir = new File(Utils.getExternalCacheDir(context), uniqueName);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            if (dir.exists() && dir.canWrite() && dir.canRead()) {
                return dir;
            }
        }

        File dir = new File(context.getCacheDir() + File.separator + uniqueName);
        dir.mkdirs();
        return dir;
    }

    public static String compressNoLargePhoto(Context context, File src) {
        try {
            return Luban.with(context).load(src).get().getPath();
        } catch (IOException e) {
            e.printStackTrace();
            return src.getPath();
        }
    }

    public static String compressNoLargePhoto(Bitmap bitmapOrg, File destFile, int maxLimit) {
        int quality = NetworkUtil.isWifiEnabled(BaseApp.getInstance()) ? QUALITY_WIFI : QUALITY_NOT_WIFI;
        return compressNoLargePhoto(bitmapOrg, destFile, quality, maxLimit, 0);
    }

    public static String compressNoLargePhoto(Bitmap bitmapOrg, File destFile, int quality, int maxLimit, int degree) {
        FileOutputStream os = null;
        try {
            if (bitmapOrg == null) {
                destFile.delete();
                return "";
            } else {
                // bitmapOrg = scaleAndRotateBitmap(bitmapOrg,srcFile);
                if (degree == 0) {
                    int orgWidth = bitmapOrg.getWidth();
                    int orgHeight = bitmapOrg.getHeight();
                    if (orgWidth > maxLimit || orgHeight > maxLimit) {
                        bitmapOrg = scaleBitmap(bitmapOrg, maxLimit);
                    }
                } else {
                    bitmapOrg = scaleAndRotateBitmap(bitmapOrg, degree, maxLimit);
                }
                if (bitmapOrg == null) {
                    return "";
                }
                // 压图
                try {
                    os = new FileOutputStream(destFile);
                    boolean compressReulst = bitmapOrg.compress(Bitmap.CompressFormat.JPEG, quality, os);

                    if (compressReulst) {
                        forceSyncFile(os);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (os != null) {
                        try {
                            os.close();
                        } catch (IOException e) {
                        }
                    }
                }
            }
        } catch (OutOfMemoryError error) {
            // 这里是为了捕获写jpg文件可能产生的oom
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }
            // 不做删除，这里也是无用代码，现在每次都重新做压缩。
            // if(hasOOM && destFile.exists()){
            // destFile.delete();
            // }
            if (bitmapOrg != null && !bitmapOrg.isRecycled()) {
                bitmapOrg.recycle();
            }
        }

        return destFile.getPath();
    }

    public static Bitmap scaleBitmap(Bitmap bitmapOrg, int max) {
        if (bitmapOrg == null) {
            return null;
        }
        Matrix m = new Matrix();
        int bitmapWidth = bitmapOrg.getWidth();
        int bitmapHeight = bitmapOrg.getHeight();
        float scale = max / (Math.max(bitmapWidth, bitmapHeight) * 1.0f);
        Bitmap newBitmap = null;
        try {
            if (scale != 1.0f && scale > 0) {
                m.postScale(scale, scale);
                newBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, bitmapWidth, bitmapHeight, m, true);
            }
        } catch (Exception e) {
        } catch (OutOfMemoryError error) {
        }
        if (newBitmap != null) {
            if (bitmapOrg != null && !bitmapOrg.isRecycled() && !bitmapOrg.equals(newBitmap)) {
                bitmapOrg.recycle();
            }
            return newBitmap;
        } else {
            return bitmapOrg;
        }
    }

    public static Bitmap scaleAndRotateBitmap(Bitmap bitmapOrg, int degress, int maxLimit) {
        if (bitmapOrg == null) {
            return null;
        }
        Matrix m = new Matrix();
        int bitmapWidth = bitmapOrg.getWidth();
        int bitmapHeight = bitmapOrg.getHeight();
        int max = Math.max(bitmapWidth, bitmapHeight);
        float scale = maxLimit / (max * 1.0f);
        int rotateDegree = degress;
        Bitmap newBitmap = null;
        try {
            if (scale < 1.0f) {
                m.postScale(scale, scale);
            }
            if (rotateDegree != 0 && 0 == rotateDegree % 90) {
                m.postRotate(rotateDegree, bitmapWidth / 2f, bitmapHeight / 2f);
            }
            newBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, bitmapWidth, bitmapHeight, m, true);
        } catch (Exception e) {
        } catch (OutOfMemoryError error) {
        }
        if (newBitmap != null) {
            if (bitmapOrg != null && !bitmapOrg.isRecycled() && !bitmapOrg.equals(newBitmap)) {
                bitmapOrg.recycle();
            }
            return newBitmap;
        } else {
            return bitmapOrg;
        }
    }

    private static final void forceSyncFile(FileOutputStream os) throws IOException, SyncFailedException {
        os.flush();
        FileDescriptor fd = os.getFD();
        if (fd != null && fd.valid()) {
            fd.sync();
        }
    }

    /*
     * 外部存储设备是否就绪
     */
    public static boolean isExternalStorageMounted() {

        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
                || !Environment.getExternalStorageDirectory().canWrite()) {
            // No SD card found.
            return false;
        }
        return true;
    }


    @SuppressLint("NewApi")
    public static File getExternalCacheDir(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
            if (context != null && context.getExternalCacheDir() != null) {
                return context.getExternalCacheDir();
            }

        }
        // Before Froyo we need to construct the external cache dir ourselves

        final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";

        File file = new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
        if (!file.exists())
            file.mkdirs();
        return file;
    }

    public static String getExternalStoragePath() {
        // 获取SdCard状态
        String state = Environment.getExternalStorageState();
        // 判断SdCard是否存在并且是可用的
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            if (Environment.getExternalStorageDirectory().canWrite()) {
                return Environment.getExternalStorageDirectory().getPath();
            }
        }
        return null;
    }

    public static boolean checkSdCardAvailable() {

        String state = Environment.getExternalStorageState();
        File sdCardDir = Environment.getExternalStorageDirectory();
        if (Environment.MEDIA_MOUNTED.equals(state) && sdCardDir.canWrite()) {
            if (getAvailableStore(sdCardDir.toString()) > LOW_STORAGE_THRESHOLD) {
                try {
                    // File f = new
                    // File(Environment.getExternalStorageDirectory(), "_temp");
                    // f.createNewFile();
                    // f.delete();
                    return true;
                } catch (Exception e) {
                }
            }
        }
        return false;

    }

    /**
     * 获取存储卡的剩余容量，单位为字节
     *
     * @param filePath
     * @return availableSpare
     */

    private static long getAvailableStore(String filePath) {
        // 取得sdcard文件路径
        StatFs statFs = new StatFs(filePath);
        // 获取block的SIZE
        long blocSize = statFs.getBlockSize();
        // 获取BLOCK数量
        long totalBlocks = statFs.getBlockCount();
        // 可使用的Block的数量
        long availaBlock = statFs.getAvailableBlocks();
        long availableSpare = availaBlock * blocSize;
        return availableSpare;

    }

    private final static String PATTERN = "yyyyMMddHHmmss";    // 时间戳命名

    public static File newTempFile(Context context) {
        String timeStamp = new SimpleDateFormat(PATTERN, Locale.CHINA).format(new Date());
        return new File(Utils.getExistCacheDir(context, UPLOAD_DIR_NAME), timeStamp + ".jpg");
    }

    public static String md5(String... args) {
        StringBuilder buffer = new StringBuilder();
        for (String arg : args) {
            buffer.append(arg);
        }
        return getMD5(buffer.toString());

    }

    /**
     * 生成md5
     *
     * @param message
     * @return
     */
    public static String getMD5(String message) {
        String md5str = "";
        try {
            // 1 创建一个提供信息摘要算法的对象，初始化为md5算法对象
            MessageDigest md = MessageDigest.getInstance("MD5");

            // 2 将消息变成byte数组
            byte[] input = message.getBytes();

            // 3 计算后获得字节数组,这就是那128位了
            byte[] buff = md.digest(input);

            // 4 把数组每一字节（一个字节占八位）换成16进制连成md5字符串
            md5str = bytesToHex(buff);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return md5str;
    }

    /**
     * 二进制转十六进制
     *
     * @param bytes
     * @return
     */
    public static String bytesToHex(byte[] bytes) {
        StringBuffer md5str = new StringBuffer();
        // 把数组每一字节换成16进制连成md5字符串
        int digital;
        for (int i = 0; i < bytes.length; i++) {
            digital = bytes[i];

            if (digital < 0) {
                digital += 256;
            }
            if (digital < 16) {
                md5str.append("0");
            }
            md5str.append(Integer.toHexString(digital));
        }
        return md5str.toString().toLowerCase();
    }

    public static void copyToclipboard(Context context, String content) {
        //获取剪贴版
        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
        //创建ClipData对象
        //第一个参数只是一个标记，随便传入。
        //第二个参数是要复制到剪贴版的内容
        ClipData clip = ClipData.newPlainText("clipboard text", content);
        //传入clipdata对象.
        clipboard.setPrimaryClip(clip);
    }

    public static String getHidePhone(String phone) {
        return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }

}
